﻿package engine.network 
{
	
	import engine.network.events.SocketRequestEvent;
	import engine.network.events.SocketResponseEvent;
	import flash.net.Socket;
	import flash.utils.ByteArray;
	
	import flash.display.Sprite;
	import flash.events.DataEvent;
	import flash.events.Event;
	import flash.events.ProgressEvent;
	import flash.net.XMLSocket;
	import flash.utils.getTimer;
	
	public class GameSocketClient extends Sprite
	{
		protected var ourSocket:Socket;
		protected var ourServerAddress:String;
		protected var ourServerPort:int;
		
		protected var ourPing:int;
		
		protected var ourStartRequestTime:int;
			
		public function GameSocketClient()
		{
			this.addEventListener(Event.ADDED_TO_STAGE,init);
			this.addEventListener(Event.REMOVED_FROM_STAGE,cleanUp);
		}
		
		protected function init(myEvent:Event):void
		{
			stage.addEventListener(SocketRequestEvent.CONNECT, connectToServer);
			stage.addEventListener(SocketRequestEvent.JOIN_GAME, passEventToServer);
			stage.addEventListener(SocketRequestEvent.CHANGE_PLAYER_STATE, passEventToServer);
			stage.addEventListener(SocketRequestEvent.CHANGE_OBJECT_STATE, passEventToServer);
			stage.addEventListener(SocketRequestEvent.SEND_CHAT, passEventToServer);
			
			
			ourSocket = new Socket();
			
			ourSocket.addEventListener(ProgressEvent.SOCKET_DATA,parseResponse);
			ourSocket.addEventListener(Event.CONNECT,connectedToServer);			
		}
		
		protected function cleanUp(myEvent:Event):void
		{
			stage.removeEventListener(SocketRequestEvent.CONNECT, connectToServer);
			stage.removeEventListener(SocketRequestEvent.JOIN_GAME, passEventToServer);
			stage.removeEventListener(SocketRequestEvent.CHANGE_PLAYER_STATE, passEventToServer);
			stage.removeEventListener(SocketRequestEvent.CHANGE_OBJECT_STATE, passEventToServer);
			stage.removeEventListener(SocketRequestEvent.SEND_CHAT, passEventToServer);

		}
		
		protected function connectedToServer(myEvent:Event):void
		{
			ourPing = flash.utils.getTimer() - ourStartRequestTime;
			var myResponseEvent:SocketResponseEvent = new SocketResponseEvent(SocketResponseEvent.CONNECTED,0,null);
			
			stage.dispatchEvent(myResponseEvent);
		}
		
		protected function connectToServer(myEvent:SocketRequestEvent):void
		{
			ourServerAddress = myEvent.parameters.address;
			ourServerPort = myEvent.parameters.port;
			
			ourStartRequestTime = flash.utils.getTimer();
			ourSocket.connect(ourServerAddress, ourServerPort);
			
		}
		
		protected function passEventToServer(myEvent:SocketRequestEvent):void
		{
			if(!ourSocket.connected)
				return;

			ourSocket.writeBytes(buildRequestPacket(myEvent));
			ourSocket.flush();
		}
		
		protected function buildRequestPacket(myEvent:SocketRequestEvent):ByteArray
		{
			var ba:ByteArray = new ByteArray();

			//add integer representation of the request type to bytes
			ba.writeByte(int(myEvent.type));
			// add integer representation of the game id to join
			ba.writeByte(myEvent.gameID);
			// add the current delay (ping)
			ba.writeShort(ourPing);

			switch (myEvent.type)
			{
				case SocketRequestEvent.JOIN_GAME:
					// No more information required in order to Join game
				break;
				case SocketRequestEvent.CHANGE_PLAYER_STATE:
					// write out the players X direction
					ba.writeShort(int(myEvent.parameters.x));
					// write out the players Y direction
					ba.writeShort(int(myEvent.parameters.y));
					// write out the players facing direction
					ba.writeByte(int(myEvent.parameters.animRow));
				break;
				case SocketRequestEvent.SEND_CHAT:
					var message:String = myEvent.parameters.message;
					ba.writeByte(message.length);
					ba.writeUTFBytes(message);
					trace(ba.length);
				break;
			}
			return ba;

			
		}
		
		protected function parseResponse(myEvent:ProgressEvent):void
		{
			var buffer:ByteArray = new ByteArray();
			this.ourSocket.readBytes(buffer);
			
			while (buffer.bytesAvailable > 0)
			{				
				var type:String = buffer.readUnsignedByte().toString();
				var myClientPing:int = 0;
				var myData:Object = {};
				myData["player_id"] = buffer.readUnsignedByte().toString();
				myData.properties = {};
			
				trace(type);
			
				switch(type)
				{
					case SocketResponseEvent.PLAYER_STATE_CHANGED:
						myData.properties["x"] = buffer.readUnsignedShort().toString();
						myData.properties["y"] = buffer.readUnsignedShort().toString();
						myData.properties["animRow"] = buffer.readUnsignedByte().toString();
					break;
					case SocketResponseEvent.INCOMING_CHAT:
						var length:int = buffer.readUnsignedByte();
						myData.properties["message"] = buffer.readUTFBytes(length);
					break;
				}

				var myResponseEvent:SocketResponseEvent = new SocketResponseEvent(type, myClientPing + ourPing, myData);
			
				stage.dispatchEvent(myResponseEvent);
			}

		}
	}
}
